package cn.amossun.starter.web.data.security.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.amossun.starter.mybatis.data.security.cache.LocalCache;
import cn.amossun.starter.mybatis.data.security.properties.ResultMapConfiguration;
import cn.amossun.starter.mybatis.data.security.rewrite.DecryptPreParameterRewriter;
import cn.amossun.starter.mybatis.data.security.rewrite.EncryptPreParameterRewriter;
import cn.amossun.starter.mybatis.data.security.runner.DecryptRuleLocalCacheRunner;
import cn.amossun.starter.mybatis.data.security.runner.OrmConfigCacheRunner;
import cn.amossun.starter.redis.cache.exception.RedisCacheConfigException;
import cn.amossun.starter.web.data.security.entity.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @description:
 * @author: Amos.Sun
 * @DateTime: 2020-03-08 16:51
 **/
@Slf4j
@RestController
@ConditionalOnBean({EncryptPreParameterRewriter.class, DecryptPreParameterRewriter.class})
public class DataSecurityController {

    @Resource
    @Qualifier("encryptPreParameterRewriter")
    private EncryptPreParameterRewriter encryptRewriter;

    @Resource
    @Qualifier("decryptPreParameterRewriter")
    private DecryptPreParameterRewriter decryptRewriter;

    @Resource
    @Qualifier("amosRedisTemplate")
    private RedisTemplate amosRedisTemplate;

    @Autowired
    private OrmConfigCacheRunner ormConfigCacheRunner;

    @Autowired
    private DecryptRuleLocalCacheRunner decryptRuleLocalCacheRunner;

    //@PostMapping("/patchOrmConfigs")
    public Result<Object> patchOrmConfigs(@RequestBody List<ResultMapConfiguration> ormConfigs) throws Exception {
        String ormCacheKey = ormConfigCacheRunner.getCacheKey();
        amosRedisTemplate.opsForValue().set(ormCacheKey, JSONUtil.toJsonStr(ormConfigs));
        ormConfigCacheRunner.getLoadingCache().refresh(ormCacheKey);  //主动刷新本地Redis缓存
        return Result.builder().data(getOrmConfigs()).build();
    }

    //@PostMapping("/removeOrmConfigs")
    public Result<Boolean> removeOrmConfigs() throws RedisCacheConfigException {
        String ormCacheKey = ormConfigCacheRunner.getCacheKey();
        if(amosRedisTemplate.hasKey(ormCacheKey) && amosRedisTemplate.delete(ormCacheKey)) {
            log.info("移除加密配置: {}", ormCacheKey);
            ormConfigCacheRunner.getLoadingCache().refresh(ormCacheKey); //删除后主动刷新本地Redis缓存
            LocalCache.removeObjectFiledCache(); //删除本地缓存
            return new Result(true);
        }
        log.info("加密配置未设置: {}", ormCacheKey);
        return new Result(false);
    }

    @GetMapping("/refreshOrmConfigs")
    public Result<Boolean> refreshOrmConfigs() throws RedisCacheConfigException {
        return new Result(ormConfigCacheRunner.refresh()); //主动刷新本地Redis缓存
    }

    @GetMapping("/getOrmConfigs")
    public Result<Object> getOrmConfigs() throws Exception {
        ormConfigCacheRunner.refresh();  //主动刷新本地Redis缓存
        Object object = ormConfigCacheRunner.getCacheValue();
        if(object != null && object instanceof Optional) {
            Optional<Object> optionalObject = (Optional<Object>)object;

            if(!optionalObject.isPresent()) {
                log.info("获取redis加解密配置json为空.");
                return new Result(object);
            }
            JSONArray jsonArray = JSONUtil.parseArray(JSONUtil.toJsonStr(optionalObject.get()));
            List<ResultMapConfiguration> ormConfigs = JSONUtil.toList(jsonArray, ResultMapConfiguration.class);
            if(CollectionUtil.isNotEmpty(ormConfigs)) {
                log.info("获取redis加解密配置json {} 个.", ormConfigs.size());
                decryptRuleLocalCacheRunner.refreshLocalCache(ormConfigs); //更新本地缓存
            }
        }
        return new Result(object);
    }

    @GetMapping("/encrypt")
    public Result<String> encrypt(@RequestParam("encryptValue") String encryptValue) {
        String encryptAfterValue = encryptRewriter.getEncryptedValueOrNull(encryptValue);
        if(log.isDebugEnabled()) {
            log.debug("加密前数据: {}, 加密后数据: {}.", encryptValue, encryptAfterValue);
        }
        return new Result(encryptAfterValue);
    }

    @GetMapping("/decrypt")
    public Result<String> decrypt(@RequestParam("decryptValue") String decryptValue) {
        String decryptAfterValue = decryptRewriter.getDecryptValueOrNull(decryptValue);
        if(log.isDebugEnabled()) {
            log.debug("解密前数据: {}, 解密后数据: {}.", decryptValue, decryptAfterValue);
        }
        return new Result(decryptAfterValue);
    }
}
